// MyStringArray.h: interface for the CStringsArray class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_MYSTRINGARRAY_H__80076C6B_FA6F_4CF8_B5B1_C5B51CEBCF4C__INCLUDED_)
#define AFX_MYSTRINGARRAY_H__80076C6B_FA6F_4CF8_B5B1_C5B51CEBCF4C__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "define.h"

#ifndef ABC_STATIC_DATA
	#define ABC_STATIC extern
	#define ABC_STATIC_DATA extern __declspec(selectany)
#endif

//struct CCStringData
//{
//	long nRefs;             // reference count
//	int nDataLength;        // length of data (including terminator)
//	int nAllocLength;       // length of allocation
//	// TCHAR data[nAllocLength]

//	TCHAR* data()           // TCHAR* to managed data
//		{ return (TCHAR*)(this+1); }
//};
//BOOL AbcIsValidAddress(const void* lp,UINT nBytes, BOOL bReadWrite = TRUE );
//BOOL AbcIsValidString(LPCSTR lpsz, int nLength = -1 );

//template<class TYPE>
//void ConstructElementss(TYPE* pElements, int nCount)
//{
//	// first do bit-wise zero initialization
//	memset((void*)pElements, 0, nCount * sizeof(TYPE));
//}

//template<class TYPE>
//void DestructElementss(TYPE* pElements, int nCount)
//{
//	// call the destructor(s)
//	for (; nCount--; pElements++)
//		pElements->~TYPE();
//}

//template<class TYPE>
//void  CopyElementss(TYPE* pDest, const TYPE* pSrc, int nCount)
//{
//	// default is element-copy using assignment
//	while (nCount--)
//		*pDest++ = *pSrc++;
//}

//template<class TYPE, class ARG_TYPE>
//BOOL CompareElementss(const TYPE* pElement1, const ARG_TYPE* pElement2)
//{
//	return *pElement1 == *pElement2;
//}

//template<class ARG_KEY>
//UINT HashKeys(ARG_KEY key)
//{
//	// default identity hash - works for most primitive values
//	return ((UINT)(void*)(DWORD)key) >> 4;
//}


class CStrings  
{
public:
	// constructs empty CString
	CStrings();
	// copy constructor
	CStrings(const CStrings& stringSrc);
    CStrings(const std::string& stringSrc);
	// from a single character
    //CStrings(TCHAR ch, int nLength = 1);
	// from an ANSI string (converts to TCHAR)
    //CStrings(LPCSTR lpsz);
	// from unsigned characters
	CStrings(const unsigned char* lpsz);
    CStrings(const char* lpsz);
    //CStrings(LPCTSTR lpch, int nLength);
// Attributes & Operations

	// get data length
	int GetLength() const;
	// TRUE if zero length
	BOOL IsEmpty() const;
	// clear contents to empty
	void Empty();

	// return single character at zero-based index
    //TCHAR GetAt(int nIndex) const;
    char GetAt(int nIndex) const;
	// return single character at zero-based index
    //TCHAR operator[](int nIndex) const;
    char operator[](int nIndex) const;
	// set a single character at zero-based index
    //void SetAt(int nIndex, TCHAR ch);
    void SetAt(int nIndex, char ch);

	bool operator==(const CStrings& s2)
    {
        //return Compare(s2) == 0;
        return m_pchData == s2.m_pchData;
    }
    bool operator==(const std::string& s2)
    {
        return m_pchData == s2;
    }
    bool operator==(const char* s2)
    {
        return m_pchData == s2;
    }
//	bool operator==( LPCTSTR s2)
//		{ return Compare(s2) == 0; }
	bool operator!=( const CStrings& s2 )
    {
        //return Compare(s2) != 0;
        return m_pchData != s2.m_pchData;
    }
    bool operator!=(const std::string& s2)
    {
        return m_pchData != s2;
    }
    bool operator!=(const char* s2)
    {
        return m_pchData != s2;
    }
//	bool operator!=(LPCTSTR s2)
//		{ return Compare(s2) != 0; }
	bool operator<(const CStrings& s2)
    {
        //return Compare(s2) < 0;
        return m_pchData < s2.m_pchData;
    }
    bool operator<(const std::string& s2)
    {
        return m_pchData < s2;
    }
    bool operator<(const char* s2)
    {
        return m_pchData < s2;
    }
//	bool operator<(LPCTSTR s2)
//		{ return Compare(s2) < 0; }
	bool operator>(const CStrings& s2)
    {
        //return Compare(s2) > 0;
        return m_pchData > s2.m_pchData;
    }
    bool operator>(const std::string& s2)
    {
        return m_pchData > s2;
    }
    bool operator>(const char* s2)
    {
        return m_pchData > s2;
    }
//	bool operator>(LPCTSTR s2)
//		{ return Compare(s2) > 0; }
	bool operator<=(const CStrings& s2)
    {
        //return Compare(s2) <= 0;
        return m_pchData <= s2.m_pchData;
    }
    bool operator<=(const std::string& s2)
    {
        return m_pchData <= s2;
    }
    bool operator<=(const char* s2)
    {
        return m_pchData <= s2;
    }
//	bool operator<=(LPCTSTR s2)
//		{ return Compare(s2) <= 0; }
	bool operator>=(const CStrings& s2)
    {
        //return Compare(s2) >= 0;
        return m_pchData >= s2.m_pchData;
    }
    bool operator>=(const std::string& s2)
    {
        return m_pchData >= s2;
    }
    bool operator>=(const char* s2)
    {
        return m_pchData >= s2;
    }
//	bool operator>=(LPCTSTR s2)
//		{ return Compare(s2) >= 0; }
//	operator LPCTSTR() const
//		{ return m_pchData; }
    operator LPCTSTR() const
    {
        return m_pchData.c_str();
    }
    std::string string() const
    {
        return m_pchData;
    }
//    char const* c_str() const
//    {
//        return m_pchData.c_str();
//    }

	// overloaded assignment

	// ref-counted copy from another CString
	const CStrings& operator=(const CStrings& stringSrc);
    const CStrings& operator=(const std::string& stringSrc);
    const CStrings& operator=(const char* stringSrc);
	// set string content to single character
    //const CStrings& operator=(TCHAR ch);
//#ifdef _UNICODE
	const CStrings& operator=(char ch);
//#endif
	// copy string content from ANSI string (converts to TCHAR)
    //const CStrings& operator=(LPCSTR lpsz);
	// copy string content from UNICODE string (converts to TCHAR)
    //const CStrings& operator=(LPCWSTR lpsz);
	// copy string content from unsigned chars
	const CStrings& operator=(const unsigned char* psz);

	// string concatenation

	// concatenate from another CStrings
    const CStrings& operator+=(const CStrings& str);
    const CStrings& operator+=(const std::string& str);
    const CStrings& operator+=(const char * str);

	// concatenate a single character
    //const CStrings& operator+=(TCHAR ch);
//#ifdef _UNICODE
	// concatenate an ANSI character after converting it to TCHAR
	const CStrings& operator+=(char ch);
//#endif
	// concatenate a UNICODE character after converting it to TCHAR
    //const CStrings& operator+=(LPCTSTR lpsz);

    friend CStrings operator+(const CStrings& string1, const CStrings& string2);

    //friend CStrings operator+(const CStrings& string, TCHAR ch);
    //friend CStrings operator+(TCHAR ch, const CStrings& string);

	friend CStrings operator+(const CStrings& string, LPCTSTR lpsz);
	friend CStrings operator+(LPCTSTR lpsz, const CStrings& string);


	// straight character comparison
    //int Compare(LPCTSTR lpsz) const;
	// compare ignoring case
    //int CompareNoCase(LPCTSTR lpsz) const;
	// NLS aware comparison, case sensitive
    //int Collate(LPCTSTR lpsz) const;
	// NLS aware comparison, case insensitive
    //int CollateNoCase(LPCTSTR lpsz) const;
	// return nCount characters starting at zero-based nFirst

	CStrings Mid(int nFirst, int nCount) const;
	// return all characters starting at zero-based nFirst
	CStrings Mid(int nFirst) const;
	// return first nCount characters in string
	CStrings Left(int nCount) const;
	// return nCount characters from end of string
	CStrings Right(int nCount) const;

	// upper/lower/reverse conversion

	// NLS aware conversion to uppercase
	void MakeUpper();
	// NLS aware conversion to lowercase
	void MakeLower();
	// reverse string right-to-left
	void MakeReverse();

	// trimming whitespace (either side)

	// remove whitespace starting from right edge
	void TrimRight();
	// remove whitespace starting from left side
	void TrimLeft();

	// trimming anything (either side)

	// remove continuous occurrences of chTarget starting from right
    //void TrimRight(TCHAR chTarget);
	// remove continuous occcurrences of characters in passed string,
	// starting from right
    //void TrimRight(LPCTSTR lpszTargets);
	// remove continuous occurrences of chTarget starting from left
    //void TrimLeft(TCHAR chTarget);
	// remove continuous occcurrences of characters in
	// passed string, starting from left
    //void TrimLeft(LPCTSTR lpszTargets);

	// advanced manipulation

	// replace occurrences of chOld with chNew
    //int Replace(TCHAR chOld, TCHAR chNew);
	// replace occurrences of substring lpszOld with lpszNew;
	// empty lpszNew removes instances of lpszOld
	int Replace(LPCTSTR lpszOld, LPCTSTR lpszNew);
	// remove occurrences of chRemove
    int Remove(char chRemove);
	// insert character at zero-based index; concatenates
	// if index is past end of string
    int Insert(int nIndex, char ch);
	// insert substring at zero-based index; concatenates
	// if index is past end of string
	int Insert(int nIndex, LPCTSTR pstr);
	// delete nCount characters starting at zero-based index
	int Delete(int nIndex, int nCount = 1);

	// searching

	// find character starting at left, -1 if not found
    int Find(char ch) const;
	// find character starting at right
    int ReverseFind(char ch) const;
	// find character starting at zero-based index and going right
    int Find(char ch, int nStart) const;
	// find first instance of any character in passed string
    //int FindOneOf(LPCTSTR lpszCharSet) const;
	// find first instance of substring
	int Find(LPCTSTR lpszSub) const;
	// find first instance of substring starting at zero-based index
	int Find(LPCTSTR lpszSub, int nStart) const;
	
	// printf-like formatting using passed string
    //void __cdecl Format(LPCTSTR lpszFormat, ...);
    //void FormatV(LPCTSTR lpszFormat, va_list argList);
	
//    LPTSTR GetBuffer(int nMinBufLength);
    char const* GetBuffer(int nMinBufLength);
	// release buffer, setting length to nNewLength (or to first nul if -1)
    //void ReleaseBuffer(int nNewLength = -1);
	// get pointer to modifiable buffer exactly as long as nNewLength
    //LPTSTR GetBufferSetLength(int nNewLength);
	// release memory allocated to but unused by string
    //void FreeExtra();
public:
	virtual ~CStrings();
    //int GetAllocLength() const;

protected:
    //LPTSTR m_pchData;   // pointer to ref counted string data
    std::string m_pchData;
	// implementation helpers
    //CCStringData* GetData() const;

    //void Init();
    //void AllocCopy(CStrings& dest, int nCopyLen, int nCopyIndex, int nExtraLen) const;
    //void AllocBuffer(int nLen);
    //void AssignCopy(int nSrcLen, LPCTSTR lpszSrcData);
    //void ConcatCopy(int nSrc1Len, LPCTSTR lpszSrc1Data, int nSrc2Len, LPCTSTR lpszSrc2Data);
    //void ConcatInPlace(int nSrcLen, LPCTSTR lpszSrcData);
    //void CopyBeforeWrite();
    //void AllocBeforeWrite(int nLen);
    //void Release();
    //static void PASCAL   Release(CCStringData* pData);
    //static int  PASCAL   SafeStrlen(LPCTSTR lpsz);
    //static void FreeData(CCStringData* pData);
};

//########################################################################################################

class CStringsArray  
{
public:
	CStringsArray();
	virtual ~CStringsArray();
// Attributes
	int GetSize() const
    {
        //return m_nSize;
        return static_cast<int>(m_pData.size());
    }
//	int GetUpperBound() const
//		{ return m_nSize-1; }
//	void SetSize(int nNewSize, int nGrowBy = -1);
//	void FreeExtra();
	void RemoveAll()
    {
        //SetSize(0);
        m_pData.clear();
    }

	// Accessing elements
	CStrings GetAt(int nIndex) const;
	void SetAt(int nIndex, LPCTSTR newElement)
		{ m_pData[nIndex] = newElement; }

	void SetAt(int nIndex, const CStrings& newElement)
		{ m_pData[nIndex] = newElement; }

	CStrings& ElementAt(int nIndex)
		{ return m_pData[nIndex]; }

	// Direct Access to the element data (may return NULL)
//	const CStrings* GetData() const
//		{ return (const CStrings*)m_pData; }
//	CStrings* GetData()
//		{ return (CStrings*)m_pData; }

	// Potentially growing the array
//	void SetAtGrow(int nIndex, LPCTSTR newElement);

//	void SetAtGrow(int nIndex, const CStrings& newElement);

	int Add(LPCTSTR newElement);

	int Add(const CStrings& newElement)
    {
//        int nIndex = m_nSize;
//        SetAtGrow(nIndex, newElement);
//        return nIndex;
        int nIndex = GetSize();
        m_pData.push_back(newElement);
        return nIndex;
    }

	int Append(const CStringsArray& src);
//	void Copy(const CStringsArray& src);

	// overloaded operator helpers
	CStrings operator[](int nIndex) const
		{ return GetAt(nIndex); }
	CStrings& operator[](int nIndex)
		{ return ElementAt(nIndex); }

	// Operations that move elements around
	void InsertAt(int nIndex, LPCTSTR newElement, int nCount = 1);

	void InsertAt(int nIndex, const CStrings& newElement, int nCount = 1);

    //void RemoveAt(int nIndex, int nCount = 1);
    //void InsertAt(int nStartIndex, CStringsArray* pNewArray);

// Implementation
protected:
    std::vector<CStrings> m_pData;
    //CStrings* m_pData;   // the actual array of data
    //int m_nSize;     // # of elements (upperBound - 1)
    //int m_nMaxSize;  // max allocated
    //int m_nGrowBy;   // grow amount

    //void InsertEmpty(int nIndex, int nCount);

//protected:
	// local typedefs for class templates
    //typedef CStrings BASE_TYPE;
    //typedef LPCTSTR  BASE_ARG_TYPE;
};

//########################################################################################################
//template<class TYPE, class ARG_TYPE>

//class CArrays
//{
//public:
//// Construction
//	CArrays();
//	virtual ~CArrays();

//// Attributes
//	int GetSize() const;
//	int GetUpperBound() const;
//	void SetSize(int nNewSize, int nGrowBy = -1);

//// Operations
//	// Clean up
//	void FreeExtra();
//	void RemoveAll();

//	// Accessing elements
//	TYPE GetAt(int nIndex) const;
//	void SetAt(int nIndex, ARG_TYPE newElement);
//	TYPE& ElementAt(int nIndex);

//	// Direct Access to the element data (may return NULL)
//	const TYPE* GetData() const;
//	TYPE* GetData();

//	// Potentially growing the array
//	void SetAtGrow(int nIndex, ARG_TYPE newElement);
//	int Add(ARG_TYPE newElement);
//	int Append(const CArrays& src);
//	void Copy(const CArrays& src);

//	// overloaded operator helpers
//	TYPE operator[](int nIndex) const;
//	TYPE& operator[](int nIndex);

//	// Operations that move elements around
//	void InsertAt(int nIndex, ARG_TYPE newElement, int nCount = 1);
//	void RemoveAt(int nIndex, int nCount = 1);
//	void InsertAt(int nStartIndex, CArrays* pNewArray);

//// Implementation
//protected:
//	TYPE* m_pData;   // the actual array of data
//	int m_nSize;     // # of elements (upperBound - 1)
//	int m_nMaxSize;  // max allocated
//	int m_nGrowBy;   // grow amount

//};

//// CArrays<TYPE, ARG_TYPE> inline functions

//template<class TYPE, class ARG_TYPE>
//int CArrays<TYPE, ARG_TYPE>::GetSize() const
//	{ return m_nSize; }
//template<class TYPE, class ARG_TYPE>
//int CArrays<TYPE, ARG_TYPE>::GetUpperBound() const
//	{ return m_nSize-1; }
//template<class TYPE, class ARG_TYPE>
//void CArrays<TYPE, ARG_TYPE>::RemoveAll()
//	{ SetSize(0, -1); }
//template<class TYPE, class ARG_TYPE>
//TYPE CArrays<TYPE, ARG_TYPE>::GetAt(int nIndex) const
//	{ return m_pData[nIndex]; }
//template<class TYPE, class ARG_TYPE>
//void CArrays<TYPE, ARG_TYPE>::SetAt(int nIndex, ARG_TYPE newElement)
//	{ m_pData[nIndex] = newElement; }
//template<class TYPE, class ARG_TYPE>
//TYPE& CArrays<TYPE, ARG_TYPE>::ElementAt(int nIndex)
//	{ return m_pData[nIndex]; }
//template<class TYPE, class ARG_TYPE>
//const TYPE* CArrays<TYPE, ARG_TYPE>::GetData() const
//	{ return (const TYPE*)m_pData; }
//template<class TYPE, class ARG_TYPE>
//TYPE* CArrays<TYPE, ARG_TYPE>::GetData()
//	{ return (TYPE*)m_pData; }
//template<class TYPE, class ARG_TYPE>
//int CArrays<TYPE, ARG_TYPE>::Add(ARG_TYPE newElement)
//	{ int nIndex = m_nSize;
//		SetAtGrow(nIndex, newElement);
//		return nIndex; }
//template<class TYPE, class ARG_TYPE>
//TYPE CArrays<TYPE, ARG_TYPE>::operator[](int nIndex) const
//	{ return GetAt(nIndex); }
//template<class TYPE, class ARG_TYPE>
//TYPE& CArrays<TYPE, ARG_TYPE>::operator[](int nIndex)
//	{ return ElementAt(nIndex); }

///////////////////////////////////////////////////////////////////////////////
//// CArrays<TYPE, ARG_TYPE> out-of-line functions

//template<class TYPE, class ARG_TYPE>
//CArrays<TYPE, ARG_TYPE>::CArrays()
//{
//	m_pData = NULL;
//	m_nSize = m_nMaxSize = m_nGrowBy = 0;
//}

//template<class TYPE, class ARG_TYPE>
//CArrays<TYPE, ARG_TYPE>::~CArrays()
//{
//	if (m_pData != NULL)
//	{
//		DestructElementss<TYPE>(m_pData, m_nSize);
//		delete[] (BYTE*)m_pData;
//	}
//}

//template<class TYPE, class ARG_TYPE>
//void CArrays<TYPE, ARG_TYPE>::SetSize(int nNewSize, int nGrowBy)
//{
//	if (nGrowBy != -1)
//		m_nGrowBy = nGrowBy;  // set new size

//	if (nNewSize == 0)
//	{
//		// shrink to nothing
//		if (m_pData != NULL)
//		{
//			DestructElementss<TYPE>(m_pData, m_nSize);
//			delete[] (BYTE*)m_pData;
//			m_pData = NULL;
//		}
//		m_nSize = m_nMaxSize = 0;
//	}
//	else if (m_pData == NULL)
//	{
//		// create one with exact size
//		m_pData = (TYPE*) new BYTE[nNewSize * sizeof(TYPE)];
//		ConstructElementss<TYPE>(m_pData, nNewSize);
//		m_nSize = m_nMaxSize = nNewSize;
//	}
//	else if (nNewSize <= m_nMaxSize)
//	{
//		// it fits
//		if (nNewSize > m_nSize)
//		{
//			// initialize the new elements
//			ConstructElementss<TYPE>(&m_pData[m_nSize], nNewSize-m_nSize);
//		}
//		else if (m_nSize > nNewSize)
//		{
//			// destroy the old elements
//			DestructElementss<TYPE>(&m_pData[nNewSize], m_nSize-nNewSize);
//		}
//		m_nSize = nNewSize;
//	}
//	else
//	{
//		// otherwise, grow array
//		int nGrowBy = m_nGrowBy;
//		if (nGrowBy == 0)
//		{
//			// heuristically determine growth when nGrowBy == 0
//			//  (this avoids heap fragmentation in many situations)
//			nGrowBy = m_nSize / 8;
//			nGrowBy = (nGrowBy < 4) ? 4 : ((nGrowBy > 1024) ? 1024 : nGrowBy);
//		}
//		int nNewMax;
//		if (nNewSize < m_nMaxSize + nGrowBy)
//			nNewMax = m_nMaxSize + nGrowBy;  // granularity
//		else
//			nNewMax = nNewSize;  // no slush

//		TYPE* pNewData = (TYPE*) new BYTE[nNewMax * sizeof(TYPE)];

//		// copy new data from old
//		memcpy(pNewData, m_pData, m_nSize * sizeof(TYPE));

//		// construct remaining elements
//		ConstructElementss<TYPE>(&pNewData[m_nSize], nNewSize-m_nSize);

//		// get rid of old stuff (note: no destructors called)
//		delete[] (BYTE*)m_pData;
//		m_pData = pNewData;
//		m_nSize = nNewSize;
//		m_nMaxSize = nNewMax;
//	}
//}

//template<class TYPE, class ARG_TYPE>
//int CArrays<TYPE, ARG_TYPE>::Append(const CArrays& src)
//{
//	int nOldSize = m_nSize;
//	SetSize(m_nSize + src.m_nSize);
//	CopyElements<TYPE>(m_pData + nOldSize, src.m_pData, src.m_nSize);
//	return nOldSize;
//}

//template<class TYPE, class ARG_TYPE>
//void CArrays<TYPE, ARG_TYPE>::Copy(const CArrays& src)
//{
//	SetSize(src.m_nSize);
//	CopyElements<TYPE>(m_pData, src.m_pData, src.m_nSize);
//}

//template<class TYPE, class ARG_TYPE>
//void CArrays<TYPE, ARG_TYPE>::FreeExtra()
//{

//	if (m_nSize != m_nMaxSize)
//	{
//		// shrink to desired size
//		TYPE* pNewData = NULL;
//		if (m_nSize != 0)
//		{
//			pNewData = (TYPE*) new BYTE[m_nSize * sizeof(TYPE)];
//			// copy new data from old
//			memcpy(pNewData, m_pData, m_nSize * sizeof(TYPE));
//		}

//		// get rid of old stuff (note: no destructors called)
//		delete[] (BYTE*)m_pData;
//		m_pData = pNewData;
//		m_nMaxSize = m_nSize;
//	}
//}

//template<class TYPE, class ARG_TYPE>
//void CArrays<TYPE, ARG_TYPE>::SetAtGrow(int nIndex, ARG_TYPE newElement)
//{
//	if (nIndex >= m_nSize)
//		SetSize(nIndex+1, -1);
//	m_pData[nIndex] = newElement;
//}

//template<class TYPE, class ARG_TYPE>
//void CArrays<TYPE, ARG_TYPE>::InsertAt(int nIndex, ARG_TYPE newElement, int nCount /*=1*/)
//{
//	if (nIndex >= m_nSize)
//	{
//		// adding after the end of the array
//		SetSize(nIndex + nCount, -1);   // grow so nIndex is valid
//	}
//	else
//	{
//		// inserting in the middle of the array
//		int nOldSize = m_nSize;
//		SetSize(m_nSize + nCount, -1);  // grow it to new size
//		// destroy intial data before copying over it
//		DestructElementss<TYPE>(&m_pData[nOldSize], nCount);
//		// shift old data up to fill gap
//		memmove(&m_pData[nIndex+nCount], &m_pData[nIndex],
//			(nOldSize-nIndex) * sizeof(TYPE));

//		// re-init slots we copied from
//		ConstructElementss<TYPE>(&m_pData[nIndex], nCount);
//	}

//	// insert new value in the gap
//	while (nCount--)
//		m_pData[nIndex++] = newElement;
//}

//template<class TYPE, class ARG_TYPE>
//void CArrays<TYPE, ARG_TYPE>::RemoveAt(int nIndex, int nCount)
//{
//	// just remove a range
//	int nMoveCount = m_nSize - (nIndex + nCount);
//	DestructElementss<TYPE>(&m_pData[nIndex], nCount);
//	if (nMoveCount)
//		memmove(&m_pData[nIndex], &m_pData[nIndex + nCount],
//			nMoveCount * sizeof(TYPE));
//	m_nSize -= nCount;
//}

//template<class TYPE, class ARG_TYPE>
//void CArrays<TYPE, ARG_TYPE>::InsertAt(int nStartIndex, CArrays* pNewArray)
//{
//	if (pNewArray->GetSize() > 0)
//	{
//		InsertAt(nStartIndex, pNewArray->GetAt(0), pNewArray->GetSize());
//		for (int i = 0; i < pNewArray->GetSize(); i++)
//			SetAt(nStartIndex + i, pNewArray->GetAt(i));
//	}
//}

////#pragma pack( push, 4 )
////#pragma pack( pop )

//// abstract iteration position
//struct __POSITIONS { };
//typedef __POSITIONS* POSITIONS;

//#define BEFORE_START_POSITIONS ((POSITIONS)-1L)


//struct CPlexs     // warning variable length structure
//{
//	CPlexs* pNext;
//#if (_AFX_PACKING >= 8)
//	DWORD dwReserved[1];    // align on 8 byte boundary
//#endif
//	// BYTE data[maxNum*elementSize];

//	void* data() { return this+1; }

//	static CPlexs* PASCAL Create(CPlexs*& head, UINT nMax, UINT cbElement);
//			// like 'calloc' but no zero fill
//			// may throw memory exceptions

//	void FreeDataChain();       // free this one and links
//};


//template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>

//class CMaps
//{
//protected:
//	// Association
//	struct CAssoc
//	{
//		CAssoc* pNext;
//		UINT nHashValue;  // needed for efficient iteration
//		KEY key;
//		VALUE value;
//	};
//public:
//// Construction
//	CMaps(int nBlockSize = 30);

//// Attributes
//	// number of elements
//	int GetCount() const;
//	BOOL IsEmpty() const;

//	// Lookup
//	BOOL Lookup(ARG_KEY key, VALUE& rValue) const;

//// Operations
//	// Lookup and add if not there
//	VALUE& operator[](ARG_KEY key);

//	// add a new (key, value) pair
//	void SetAt(ARG_KEY key, ARG_VALUE newValue);

//	// removing existing (key, ?) pair
//	BOOL RemoveKey(ARG_KEY key);
//	void RemoveAll();

//	// iterating all (key, value) pairs
//	POSITIONS GetStartPosition() const;
//	void GetNextAssoc(POSITIONS& rNextPosition, KEY& rKey, VALUE& rValue) const;

//	// advanced features for derived classes
//	UINT GetHashTableSize() const;
//	void InitHashTable(UINT hashSize, BOOL bAllocNow = TRUE);

//// Implementation
//protected:
//	CAssoc** m_pHashTable;
//	UINT m_nHashTableSize;
//	int m_nCount;
//	CAssoc* m_pFreeList;
//	struct CPlexs* m_pBlocks;
//	int m_nBlockSize;

//	CAssoc* NewAssoc();
//	void FreeAssoc(CAssoc*);
//	CAssoc* GetAssocAt(ARG_KEY, UINT&) const;

//public:
//	~CMaps();
//};
	
//template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
//CMaps<KEY, ARG_KEY, VALUE, ARG_VALUE>::CMaps(int nBlockSize)
//{
//	m_pHashTable = NULL;
//	m_nHashTableSize = 17;  // default size
//	m_nCount = 0;
//	m_pFreeList = NULL;
//	m_pBlocks = NULL;
//	m_nBlockSize = nBlockSize;
//}

//template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
//CMaps<KEY, ARG_KEY, VALUE, ARG_VALUE>::~CMaps()
//{
//	RemoveAll();
//}

//template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
//int CMaps<KEY, ARG_KEY, VALUE, ARG_VALUE>::GetCount() const
//	{ return m_nCount; }
//template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
//BOOL CMaps<KEY, ARG_KEY, VALUE, ARG_VALUE>::IsEmpty() const
//	{ return m_nCount == 0; }
//template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
//void CMaps<KEY, ARG_KEY, VALUE, ARG_VALUE>::SetAt(ARG_KEY key, ARG_VALUE newValue)
//	{ (*this)[key] = newValue; }
//template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
//POSITIONS CMaps<KEY, ARG_KEY, VALUE, ARG_VALUE>::GetStartPosition() const
//	{ return (m_nCount == 0) ? NULL : BEFORE_START_POSITIONS; }
//template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
//UINT CMaps<KEY, ARG_KEY, VALUE, ARG_VALUE>::GetHashTableSize() const
//	{ return m_nHashTableSize; }

///////////////////////////////////////////////////////////////////////////////
//// CMaps<KEY, ARG_KEY, VALUE, ARG_VALUE> out-of-line functions


//template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
//void CMaps<KEY, ARG_KEY, VALUE, ARG_VALUE>::InitHashTable(
//	UINT nHashSize, BOOL bAllocNow)
////
//// Used to force allocation of a hash table or to override the default
////   hash table size of (which is fairly small)
//{
//	if (m_pHashTable != NULL)
//	{
//		// free hash table
//		delete[] m_pHashTable;
//		m_pHashTable = NULL;
//	}

//	if (bAllocNow)
//	{
//		m_pHashTable = new CAssoc* [nHashSize];
//		memset(m_pHashTable, 0, sizeof(CAssoc*) * nHashSize);
//	}
//	m_nHashTableSize = nHashSize;
//}

//template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
//void CMaps<KEY, ARG_KEY, VALUE, ARG_VALUE>::RemoveAll()
//{
//	if (m_pHashTable != NULL)
//	{
//		// destroy elements (values and keys)
//		for (UINT nHash = 0; nHash < m_nHashTableSize; nHash++)
//		{
//			CAssoc* pAssoc;
//			for (pAssoc = m_pHashTable[nHash]; pAssoc != NULL;
//			  pAssoc = pAssoc->pNext)
//			{
//				DestructElementss<VALUE>(&pAssoc->value, 1);
//				DestructElementss<KEY>(&pAssoc->key, 1);
//			}
//		}
//	}

//	// free hash table
//	delete[] m_pHashTable;
//	m_pHashTable = NULL;

//	m_nCount = 0;
//	m_pFreeList = NULL;
//	m_pBlocks->FreeDataChain();
//	m_pBlocks = NULL;
//}

//template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
//CMaps<KEY, ARG_KEY, VALUE, ARG_VALUE>::CAssoc*
//CMaps<KEY, ARG_KEY, VALUE, ARG_VALUE>::NewAssoc()
//{
//	if (m_pFreeList == NULL)
//	{
//		// add another block
//		CPlexs* newBlock = CPlexs::Create(m_pBlocks, m_nBlockSize, sizeof(CMaps::CAssoc));
//		// chain them into free list
//		CMaps::CAssoc* pAssoc = (CMaps::CAssoc*) newBlock->data();
//		// free in reverse order to make it easier to debug
//		pAssoc += m_nBlockSize - 1;
//		for (int i = m_nBlockSize-1; i >= 0; i--, pAssoc--)
//		{
//			pAssoc->pNext = m_pFreeList;
//			m_pFreeList = pAssoc;
//		}
//	}
//	CMaps::CAssoc* pAssoc = m_pFreeList;
//	m_pFreeList = m_pFreeList->pNext;
//	m_nCount++;
//	ConstructElementss<KEY>(&pAssoc->key, 1);
//	ConstructElementss<VALUE>(&pAssoc->value, 1);   // special construct values
//	return pAssoc;
//}

//template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
//void CMaps<KEY, ARG_KEY, VALUE, ARG_VALUE>::FreeAssoc(CMaps::CAssoc* pAssoc)
//{
//	DestructElementss<VALUE>(&pAssoc->value, 1);
//	DestructElementss<KEY>(&pAssoc->key, 1);
//	pAssoc->pNext = m_pFreeList;
//	m_pFreeList = pAssoc;
//	m_nCount--;
//	// if no more elements, cleanup completely
//	if (m_nCount == 0)
//		RemoveAll();
//}

//template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
//CMaps<KEY, ARG_KEY, VALUE, ARG_VALUE>::CAssoc*
//CMaps<KEY, ARG_KEY, VALUE, ARG_VALUE>::GetAssocAt(ARG_KEY key, UINT& nHash) const
//// find association (or return NULL)
//{
//	nHash = HashKeys<ARG_KEY>(key) % m_nHashTableSize;

//	if (m_pHashTable == NULL)
//		return NULL;

//	// see if it exists
//	CAssoc* pAssoc;
//	for (pAssoc = m_pHashTable[nHash]; pAssoc != NULL; pAssoc = pAssoc->pNext)
//	{
//		if (CompareElementss(&pAssoc->key, &key))
//			return pAssoc;
//	}
//	return NULL;
//}

//template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
//BOOL CMaps<KEY, ARG_KEY, VALUE, ARG_VALUE>::Lookup(ARG_KEY key, VALUE& rValue) const
//{
//	UINT nHash;
//	CAssoc* pAssoc = GetAssocAt(key, nHash);
//	if (pAssoc == NULL)
//		return FALSE;  // not in map

//	rValue = pAssoc->value;
//	return TRUE;
//}

//template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
//VALUE& CMaps<KEY, ARG_KEY, VALUE, ARG_VALUE>::operator[](ARG_KEY key)
//{

//	UINT nHash;
//	CAssoc* pAssoc;
//	if ((pAssoc = GetAssocAt(key, nHash)) == NULL)
//	{
//		if (m_pHashTable == NULL)
//			InitHashTable(m_nHashTableSize);

//		// it doesn't exist, add a new Association
//		pAssoc = NewAssoc();
//		pAssoc->nHashValue = nHash;
//		pAssoc->key = key;
//		// 'pAssoc->value' is a constructed object, nothing more

//		// put into hash table
//		pAssoc->pNext = m_pHashTable[nHash];
//		m_pHashTable[nHash] = pAssoc;
//	}
//	return pAssoc->value;  // return new reference
//}

//template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
//BOOL CMaps<KEY, ARG_KEY, VALUE, ARG_VALUE>::RemoveKey(ARG_KEY key)
//// remove key - return TRUE if removed
//{

//	if (m_pHashTable == NULL)
//		return FALSE;  // nothing in the table

//	CAssoc** ppAssocPrev;
//	ppAssocPrev = &m_pHashTable[HashKeys<ARG_KEY>(key) % m_nHashTableSize];

//	CAssoc* pAssoc;
//	for (pAssoc = *ppAssocPrev; pAssoc != NULL; pAssoc = pAssoc->pNext)
//	{
//		if (CompareElementss(&pAssoc->key, &key))
//		{
//			// remove it
//			*ppAssocPrev = pAssoc->pNext;  // remove from list
//			FreeAssoc(pAssoc);
//			return TRUE;
//		}
//		ppAssocPrev = &pAssoc->pNext;
//	}
//	return FALSE;  // not found
//}

//template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
//void CMaps<KEY, ARG_KEY, VALUE, ARG_VALUE>::GetNextAssoc(POSITIONS& rNextPosition,
//	KEY& rKey, VALUE& rValue) const
//{
//	CAssoc* pAssocRet = (CAssoc*)rNextPosition;
//	if (pAssocRet == (CAssoc*) BEFORE_START_POSITIONS)
//	{
//		// find the first association
//		for (UINT nBucket = 0; nBucket < m_nHashTableSize; nBucket++)
//			if ((pAssocRet = m_pHashTable[nBucket]) != NULL)
//				break;
//	}

//	// find next association
//	CAssoc* pAssocNext;
//	if ((pAssocNext = pAssocRet->pNext) == NULL)
//	{
//		// go to next bucket
//		for (UINT nBucket = pAssocRet->nHashValue + 1;
//		  nBucket < m_nHashTableSize; nBucket++)
//			if ((pAssocNext = m_pHashTable[nBucket]) != NULL)
//				break;
//	}

//	rNextPosition = (POSITIONS) pAssocNext;

//	// fill in return data
//	rKey = pAssocRet->key;
//	rValue = pAssocRet->value;
//}

//class CFiles
//{

//public:
//// Flag values
//	enum OpenFlags {
//		modeRead =          0x0000,
//		modeWrite =         0x0001,
//		modeReadWrite =     0x0002,
//		shareCompat =       0x0000,
//		shareExclusive =    0x0010,
//		shareDenyWrite =    0x0020,
//		shareDenyRead =     0x0030,
//		shareDenyNone =     0x0040,
//		modeNoInherit =     0x0080,
//		modeCreate =        0x1000,
//		modeNoTruncate =    0x2000,
//		typeText =          0x4000, // typeText and typeBinary are used in
//		typeBinary =   (int)0x8000 // derived classes only
//		};
//	enum Attribute {
//		normal =    0x00,
//		readOnly =  0x01,
//		hidden =    0x02,
//		system =    0x04,
//		volume =    0x08,
//		directory = 0x10,
//		archive =   0x20
//		};
//	enum SeekPosition { begin = 0x0, current = 0x1, end = 0x2 };
//	enum { hFileNull = -1 };

//// Constructors
//	CFiles();
//	CFiles(LPCTSTR lpszFileName, UINT nOpenFlags);
//	UINT m_hFile;

//// Operations
//	BOOL Open(LPCTSTR lpszFileName, UINT nOpenFlags);

//	DWORD SeekToEnd();
//	void SeekToBegin();
//	// backward compatible ReadHuge and WriteHuge
//// Overridables
//	DWORD Seek(LONG lOff, UINT nFrom);
//	DWORD GetLength() const;
//	UINT Read(void* lpBuf, UINT nCount);
//	void Write(const void* lpBuf, UINT nCount);
//	void Close();
//	void Abort();
//// Implementation
//public:
//	virtual ~CFiles();
//protected:
//	BOOL m_bCloseOnDelete;
//};

//class CStdioFiles : public CFiles
//{
//public:
//// Constructors
//    CStdioFile();
//    CStdioFile(FILE* pOpenStream);
//    CStdioFile(LPCTSTR lpszFileName, UINT nOpenFlags);

//// Attributes
//    FILE* m_pStream;    // stdio FILE
//                        // m_hFile from base class is _fileno(m_pStream)

//// Operations
//    // reading and writing strings
//    virtual void WriteString(LPCTSTR lpsz);
//    virtual LPTSTR ReadString(LPTSTR lpsz, UINT nMax);
//    virtual BOOL ReadString(CStrings& rString);

//// Implementation
//public:
//    virtual ~CStdioFile();
//    virtual DWORD GetPosition() const;
//    virtual BOOL Open(LPCTSTR lpszFileName, UINT nOpenFlags);
//    virtual UINT Read(void* lpBuf, UINT nCount);
//    virtual void Write(const void* lpBuf, UINT nCount);
//    virtual LONG Seek(LONG lOff, UINT nFrom);
//    virtual void Abort();
//    virtual void Flush();
//    virtual void Close();
//};


#endif // !defined(AFX_MYSTRINGARRAY_H__80076C6B_FA6F_4CF8_B5B1_C5B51CEBCF4C__INCLUDED_)
